#pragma once

#include "Structs.h"

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix1_functions.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/variant.hpp>


namespace GenParser
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;
	
	template <typename Iterator>
	struct GenGrammar : qi::grammar<Iterator, ModelDef(), ascii::space_type>
	{
		GenGrammar() : GenGrammar::base_type(start)
		{			
			word %= ascii::alpha >> *ascii::alnum;
			words %= (word % ',');
			 
			empty = qi::eps;

			operationParticipants %= (qi::lit("(") >> words >> qi::lit(")")) | qi::eps;
			singleOperation %= word >> operationParticipants;
			operations %= word >> qi::lit("can") >> (singleOperation % ',');
			abstractOperations %= word >> qi::lit("specify") >> (singleOperation % ',');

			generalization %= word >> qi::lit("is") >> word;
			implementation %= word >> qi::lit("implements") >> word;
			contains %= word >> (qi::lit("contains") | qi::lit("has")) >> words;

			composition %= qi::lit("Composition") >> word >> 
				qi::lit("has") >> words >> qi::lit("leafs") >> 
				qi::lit("and") >> words >> qi::lit("composites");
				
			sentence %= operations | abstractOperations | generalization | implementation |
				contains | composition | empty;
			start %= (sentence % '.') >> !qi::lit(".");
		}
		
		qi::rule<Iterator, std::wstring()> word;
		qi::rule<Iterator, std::vector<std::wstring>(), ascii::space_type> words;
		
		qi::rule<Iterator, std::vector<std::wstring>(), ascii::space_type> operationParticipants;
		qi::rule<Iterator, SingleOperationDef(), ascii::space_type> singleOperation;
		qi::rule<Iterator, OperationsDef(), ascii::space_type> operations;
		qi::rule<Iterator, AbstractOperationsDef(), ascii::space_type> abstractOperations;

		qi::rule<Iterator, EmptyItem(), ascii::space_type> empty;
		qi::rule<Iterator, GeneralizationDef(), ascii::space_type> generalization;
		qi::rule<Iterator, ImplementationDef(), ascii::space_type> implementation;
		qi::rule<Iterator, ContainsDef(), ascii::space_type> contains;
		
		qi::rule<Iterator, CompositionDef(), ascii::space_type> composition;

		qi::rule<Iterator, SemanticModelItem(), ascii::space_type> sentence;
		
		qi::rule<Iterator, ModelDef(), ascii::space_type> start;				
	};
}